// 带有管理操作的目录树
<template>
  <div class="container-menu" :style="{ height: viewHeight + 'px' }">
    <!-- 搜索区域 -->
    <div class="menu-header">
      <el-input
        v-model="filterText"
        placeholder
        id="input"
        size="mini"
        suffix-icon="el-input__icon el-icon-search"
        @keyup.enter.native="filterMenu(-1)"
      ></el-input>
    </div>
    <!-- 目录 -->
    <el-scrollbar class="scrollbar-container" wrapStyle="margin-bottom:0">
      <el-tree
        ref="tree"
        lazy
        :load="loadNode"
        node-key="id"
        :props="defaultProps"
        :highlight-current="true"
        :expand-on-click-node="false"
        :current-node-key="currentNodekey"
        :default-expanded-keys="defaultExpandKeys"
        draggable
        :allow-drop="allowDrop"
        :allow-drag="allowDrag"
        @node-drag-start="handleDragStart"
        @node-drop="handleDrop"
        @node-click="handleNodeClick"
      >
        <div
          class="custom-tree-node flex-space-between"
          slot-scope="{ node, data }"
        >
          <div class="tree-icon">
            <icon-svg class="file" icon-class="file"></icon-svg>
          </div>
          <div class="tree-label">
            <span v-show="editDirId !== data.id">
              {{ node.label }}
              <template v-if="data.num">({{ data.num }})</template>
            </span>
            <el-input
              :ref="data.id"
              v-show="editDirId === data.id"
              v-model.trim="data.title"
              size="mini"
              maxlength="15"
              @keyup.enter.native="$event.target.blur"
              @blur="labelBlur(node)"
            ></el-input>
          </div>
          <!-- 添加、编辑、删除按钮 -->
          <div class="tree-options">
            <!-- 带子节点的节点 有刷新功能 -->
            <i
              v-if="!node.isLeaf"
              class="btn blue el-icon-refresh"
              @click.stop="refreshNode(node)"
            ></i>
            <!-- 添加节点 -->
            <i class="btn blue el-icon-plus" @click.stop="addNode(node)"></i>
            <!-- 我的目录（id=-1）不能修改 -->
            <i
              v-if="data.id != -1"
              class="btn el-icon-edit"
              @click.stop="showInput(data.id, data.title)"
            ></i>
            <!-- 我的目录（id=-1）不能删除 :aaa=" data.id"-->
            <i
              v-if="data.id != -1"
              class="btn red el-icon-delete"
              @click.stop="deleteDir(node, data.id)"
            ></i>
          </div>
        </div>
      </el-tree>
    </el-scrollbar>
  </div>
</template>
 <script>
// import { isArray } from 'utils/index';
// import { mapGetters } from 'vuex';
// import {
//   getChildernDirectoryById,
//   insertDirectory,
//   updateDirectory,
//   deleteDirectoryById,
//   moveDirectory,
// } from 'api/datameta/sourceRegister/index';

export default {
  name: 'menuWithManage',
  data() {
    return {
      // 树状图默认配置
      defaultProps: {
        children: 'children',
        label: 'title',
        isLeaf: function (data, node) {
          return data.isLeaf == 'true' ? true : false;
        },
      },
      // 当前选中的节点
      currentNodekey: '',
      // 过滤文本
      filterText: '',
      // 编辑目录id：控制input框显示
      editDirId: '',
      // 编辑目录名：记录旧目录名
      oldDirName: '',
      // 默认展开的节点的 key 的数组
      defaultExpandKeys: ['-1'],
      // 新增目录id的后缀: 用于新增时起的初始目录名不重复
      dirIdSuff: 0,
      // 节点拖拽前在父节点的位置下标
      beforeDragNodeIndex: 0,
    };
  },
  computed: {
    // ...mapGetters(['viewHeight']),
  },
  methods: {
    // 获取目录列表
    getMenuList(parentId, success, error) {
      getChildernDirectoryById({
        directoryId: parentId,
        dirName: this.filterText,
      })
        .then((res) => {
          // 获取"我的目录"子节点时， 更新"我的目录"的资源条数
          if (parentId == -1) {
            this.$refs.tree.getNode(-1).data.num = res.data.num;
          }
          success ? success(res.data.dirInfo) : '';
        })
        .catch((res) => {
          error ? error(res) : '';
        });
    },

    // 点击节点的回调 node-click
    handleNodeClick(data, node) {
      this.$emit('chooseMenuItem', data, node);

      
      const res = this.$refs.tree.getCheckedKeys();
      // .concat(this.$refs.tree.getHalfCheckedKeys());

      // 全选 getCheckedKeys()
      // 半选 getHalfCheckedKeys()
    },

    // 子节点加载方法
    loadNode(node, resolve) {
      if (node.level === 0) {
        return resolve([
          {
            id: '-1',
            title: '我的目录',
            path: '/-1',
            num: 0,
            isLeaf: false,
          },
        ]);
      } else {
        this.getMenuList(
          node.data.id,
          (data) => {
            resolve(data);
          },
          (error) => {
            resolve([]);
          },
        );
      }
    },

    // 允许放置的节点设置
    allowDrop(draggingNode, dropNode, type) {
      if (dropNode.data.id == -1) {
        return type === 'inner';
      } else {
        return true;
      }
    },

    // 允许拖拽的节点设置
    allowDrag(draggingNode) {
      return draggingNode.data.id != -1;
    },

    // 拖拽前: 保存被拖拽元素的下标
    handleDragStart(draggingNode, event) {
      draggingNode.parent.childNodes.forEach((childNode, nodeIndex) => {
        if (childNode.key == draggingNode.key) {
          this.beforeDragNodeIndex = nodeIndex;
          return;
        }
      });
    },

    // 拖拽完成
    handleDrop(draggingNode, dropNode, dropType, ev) {
      // console.log('tree drop 拖拽完成: ',draggingNode.parent, dropNode.parent, dropType, ev);
      // 将dropType对应成数字
      switch (dropType) {
        case 'before':
          dropType = 0;
          break;
        case 'after':
          dropType = 1;
          break;
        case 'inner':
          dropType = 2;
          break;
        default:
          dropType = 0;
          break;
      }
      let params = {
        affectedNode: {
          id: dropNode.data.id,
          parentId: dropNode.data.parentId,
          title: dropNode.data.title,
          ord: dropNode.data.ord,
          path: dropNode.data.path,
        },
        dragNode: {
          id: draggingNode.data.id,
          parentId: draggingNode.data.parentId,
          title: draggingNode.data.title,
          ord: draggingNode.data.ord,
          path: draggingNode.data.path,
        },
        type: dropType,
      };
      moveDirectory(params)
        .then((res) => {
          console.log(res);
          // 更新节点数据
        })
        .catch(() => {
          // 删除放置的节点
          this.$refs.tree.remove(draggingNode.data);
          // 节点位置还原
          draggingNode.parent = this.$refs.tree.getNode(
            draggingNode.data.parentId,
          );
          this.$refs.tree
            .getNode(draggingNode.data.parentId)
            .childNodes.splice(this.beforeDragNodeIndex, 0, draggingNode);
        });
    },

    // 刷新指定节点
    refreshNode(node) {
      node.loaded = false;
      node.expand();
    },

    // 点击了添加子节点按钮
    addNode(node) {
      node.expand(() => {
        this.dirIdSuff = 0;
        let newDirName = this.getOnlyDirName('新建目录', node.childNodes);
        let order =
          node.childNodes.length > 0
            ? node.childNodes[node.childNodes.length - 1].data.ord + 1
            : 0;
        let newChild = {
          title: newDirName,
          isLeaf: 'true',
          ord: order,
          num: 0,
        };

        insertDirectory({
          parentId: node.data.id,
          path: node.data.path,
          title: newDirName,
          ord: order,
        }).then((res) => {
          newChild.parentId = res.data.parentId;
          newChild.id = res.data.id;
          newChild.path = res.data.path;
          this.$refs.tree.append(newChild, node);

          this.showInput(res.data.id, newChild.title);
        });
      });
    },

    // 点击了编辑按钮
    showInput(id, title) {
      this.oldDirName = title;
      this.editDirId = id;
      this.$nextTick(() => {
        this.$refs[id].focus();
      });
    },

    // 点击了删除节点
    deleteDir(node, dirId) {
      this.$confirm('确定删除[ ' + node.data.title + ' ]吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      }).then(() => {
        deleteDirectoryById({ directoryId: dirId }).then((res) => {
          this.$message({
            type: 'success',
            message: '删除成功！',
          });
          this.$refs.tree.remove(node);
        });
      });
    },

    // input失去焦点（编辑目录名）
    labelBlur(node) {
      let data = node.data;
      this.editDirId = '';
      // 名字相等的时候不用改
      if (data.title === this.oldDirName) return;
      // 检查名字是否重复
      let sameName = isArray(node.parent.childNodes)
        ? node.parent.childNodes.some(
            (childNode) =>
              childNode.data.title === data.title &&
              childNode.data.id !== data.id,
          )
        : false;
      if (sameName) {
        data.title = this.oldDirName;
        this.$message({
          type: 'error',
          message: '同目录不允许同名哦！',
        });
        return;
      }

      // 目录名称校验

      // 修改目录，调用接口
      updateDirectory({
        id: data.id,
        title: data.title,
      })
        .then((res) => {
          this.$message({ type: 'success', message: '修改成功!' });
        })
        .catch(() => {
          data.title = this.oldDirName;
        });
    },

    // 过滤函数（递归展开所有符合规则的节点）
    filterMenu(nodeId = -1) {
      // 过滤文本为空时，刷新顶级节点
      if (this.filterText.trim() == '') {
        let topNode = this.$refs.tree.getNode(-1);
        topNode.childNodes = [];
        topNode.loaded = false;
        topNode.expand();
        return;
      }
      let node = this.$refs.tree.getNode(nodeId);
      // 重新展开该节点
      console.log(nodeId);
      node.loaded = false;
      node.expand(() => {
        // 检查子元素是否有非叶子结点
        node.childNodes.forEach((item) => {
          if (item.data.isLeaf == 'false') {
            // 递归处理含有子节点的节点
            this.filterMenu(item.data.id);
          } else {
            // 递归出口
          }
        });
      });
    },

    // 寻找一个合适的目录名
    getOnlyDirName(title, arr) {
      let dirName = title + this.dirIdSuff;
      isArray(arr) ? '' : (arr = []);
      if (arr.find((val) => val.data.title === dirName)) {
        this.dirIdSuff++;
        return this.getOnlyDirName(title, arr);
      } else {
        this.dirIdSuff = 0;
        return dirName;
      }
    },

    // 寻找一个合适的目录id
    getOnlyDirId(data) {
      let dirId = data.id + '' + this.dirIdSuff;
      let arr = isArray(data.children) ? data.children : [];
      if (arr.find((val) => val.id == dirId)) {
        this.dirIdSuff++;
        return this.getOnlyDirId(data);
      } else {
        this.dirIdSuff = 0;
        return dirId;
      }
    },

    // 设置当前高亮
    setCurrentKey(dirId, dirPath) {
      let pathArr = dirPath.split('/');
      // 去掉数组首尾：首节点是空，尾节点是当前节点（同dirId）
      pathArr = pathArr.slice(1, pathArr.length - 1);
      // 展开节点的所有父级
      this.expandNodes(pathArr, 0, () => {
        // 节点展开之后触发高亮节点
        this.$refs.tree.setCurrentKey(dirId);
      });
    },

    /**
     * 循环展开节点
     * nodesArr：需要展开的节点数组
     * index：从第几个下标开始（为了方便函数递归使用）
     * expandCallback: 所有节点展开之后的回调
     */
    expandNodes(nodesArr, index = 0, expandCallback) {
      if (index < nodesArr.length) {
        this.$refs.tree.getNode(nodesArr[index]).expand(() => {
          index++;
          if (index == nodesArr.length) {
            expandCallback ? expandCallback() : '';
          } else {
            this.expandNodes(nodesArr, index, expandCallback);
          }
        });
      } else {
        // 递归出口
      }
    },
  },
};
</script>
<style lang='scss' scoped>
.container-menu{
  .menu-header{
    border-bottom: 1px solid #e8e8e8;
    /deep/.el-input__inner{
      height: 32px;
      line-height: 32px;
      border: 0;
    }
  }
  .scrollbar-container{
    height: calc(100% - 46px);
    padding-top: 7px;
  }
}
 
.custom-tree-node {
  width: calc(100% - 24px);
  font-size: 12px;
  line-height: 24px;
  align-items: center;
  .tree-icon {
    width: 20px;
    .file {
      width: 20px;
      font-size: 20px;
      vertical-align: text-bottom;
    }
  }
  
  .tree-label {
    // 100% - 50px - 20px
    width: calc(100% - 70px);
    // 1.先强制一行内显示文本
    white-space: nowrap;
    // 2.超出部分隐藏
    overflow: hidden;
    // 3.文字用省略号代替
    text-overflow: ellipsis;
    height: 24px;
    line-height: 24px;
    .el-input {
      /deep/.el-input__inner {
        height: 21px;
      }
    }
  }
  .tree-options{
    display: flex;
    justify-content: flex-end;
    opacity: 0;
    width: 50px;
    margin-right: 6px;
  }
  .btn {
    font-size: 10px;
    font-weight: bold;
  }
  .btn:nth-child(odd){
    margin: 0 4px;
  }
  .blue {
    color: #409eff;
  }
  .red {
    color: #f56c6c;
  }
}
 
// 节点hover，操作按钮显示
.custom-tree-node:hover .tree-options{
  opacity: 1 !important;
}
</style>